﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;

namespace Core.Framework.EntityExtend.AiExpression
{
    #region Model

    internal enum AiExpUnion : byte
    {
        And,
        Or
    }

    public enum AiOrderByType : byte
    {
        Asc,
        Desc
    }

    public class FiledParameter
    {
        /// <summary>
        /// 属性名
        /// </summary>
        public string name { get; set; }

        /// <summary>
        /// 是否自增
        /// </summary>
        public bool isIdentity { get; set; } = false;
    }

    #endregion

    /// <summary>
    /// Lambda转SQL语句
    /// </summary>
    /// <typeparam name="T">查询类</typeparam>
    public sealed class AiExpConditions<T>
    {
        /// <summary>
        /// 矫正词
        /// </summary>
        private Dictionary<string, FiledParameter> replace;

        public AiExpConditions(Expression<Func<T,bool>> condition = null, Dictionary<string, FiledParameter> replace = null)
        {
            if(condition != null)
                this.SetConditionWhere(condition);

            this.replace = replace;
        }

        public AiExpConditions(Dictionary<string, FiledParameter> replace = null,
            params Expression<Func<T, bool>>[] conditions)
        {
            if (conditions != null && conditions.Length > 0)
                foreach (var condition in conditions)
                    this.SetConditionWhere(condition);

            this.replace = replace;

        }

        #region 外部访问方法

        /// <summary>
        /// 获取 Where 条件语句
        /// </summary>
        /// <param name="AddCinditionKey">是否加Where词</param>
        /// <returns>Where条件语句</returns>
        public string GetWhere()
        {

            string result = string.Empty;

            foreach (var item in expressions)
            {
                if (string.IsNullOrWhiteSpace(result))
                    result = item.value;
                else
                {
                    if (item.Type == AiExpUnion.Or)
                        result = result + " Or " + item.value;
                    else
                        result = result + " And " + item.value;
                }
            }

            return this.FieldCorrection(result, this.replace);
        }

        /// <summary>
        /// 获取 OrderBy 条件语句
        /// </summary>
        /// <param name="AddCinditionKey">是否加Order By词</param>
        /// <returns>OrderBy 条件语句</returns>
        public string GetOrderBy(bool AddCinditionKey = true)
        {
            if (string.IsNullOrWhiteSpace(_aiOrderByStr)) return string.Empty;

            if (AddCinditionKey)
            {
                return " Order By " + _aiOrderByStr;
            }
            else
            {
                return _aiOrderByStr;
            }

        }

        /// <summary>
        /// 获取 KeyValue 结果
        /// </summary>
        public List<string> GetKeyValue(params Expression<Func<T, bool>>[] conditions)
        {
            foreach (var condition in conditions)
                this.SetConditionWhere(condition);

            return expressions.Select(a => this.FieldCorrection(a.value, this.replace).TrimStart('(').TrimEnd(')')).ToList();
        }


        #endregion

        #region 以 And 相联接 Where条件语句

        /// <summary>
        /// 添加一个Where条件语句，如果语句存在，则以 And 相联接
        /// </summary>
        /// <param name="aiExp">Where条件表达示</param>
        public void And(Expression<Func<T, bool>> condition)
        {
            this.SetConditionWhere(condition, AiExpUnion.And);
        }

        /// <summary>
        /// 当给定lambda表达式条件满足时,添加一个Where条件语句，如果语句存在，则以 And 相联接
        /// </summary>
        /// <param name="aiCondition">给定lambda表达式条件</param>
        /// <param name="aiExp"></param>
        public void And(Func<bool> aiCondition, Expression<Func<T, bool>> conditionWhenTrue)
        {
            if (aiCondition.Invoke())
                this.And(conditionWhenTrue);
        }

        /// <summary>
        /// 如果条件满足时,将添加前一个条件语句（Where），否则添加后一个,以 And 相联接
        /// </summary>
        /// <param name="aiCondition">Lambda条件</param>
        /// <param name="aiExpWhenTrue">条件为真时</param>
        /// <param name="aiExpWhenFalse">条件为假时</param>
        public void And(Func<bool> aiCondition, Expression<Func<T, bool>> conditionWhenTrue, Expression<Func<T, bool>> conditionWhenFalse)
        {
            if (aiCondition.Invoke())
                this.And(conditionWhenTrue);
            else
                this.And(conditionWhenFalse);
        }

        #endregion

        #region 以 Or 相联接 Where条件语句

        /// <summary>
        /// 添加一个Where条件语句，如果语句存在，则以 Or 相联接
        /// </summary>
        /// <param name="aiExp">Where条件表达示</param>
        public void Or(Expression<Func<T, bool>> condition)
        {
            this.SetConditionWhere(condition, AiExpUnion.Or);
        }

        /// <summary>
        /// 当给定lambda表达式条件满足时,添加一个Where条件语句，如果语句存在，则以 Or 相联接
        /// </summary>
        /// <param name="aiCondition">给定lambda表达式条件</param>
        /// <param name="aiExp"></param>
        public void Or(Func<bool> aiCondition, Expression<Func<T, bool>> condition)
        {
            if (aiCondition.Invoke())
                this.SetConditionWhere(condition, AiExpUnion.Or);
        }

        /// <summary>
        /// 如果条件满足时,将添加前一个条件语句（Where），否则添加后一个,以 Or 相联接
        /// </summary>
        /// <param name="aiCondition">Lambda条件</param>
        /// <param name="aiExpWhenTrue">条件为真时</param>
        /// <param name="aiExpWhenFalse">条件为假时</param>
        public void Or(Func<bool> aiCondition, Expression<Func<T, bool>> conditionWhenTrue, Expression<Func<T, bool>> conditionWhenFalse)
        {
            if (aiCondition.Invoke())
                this.SetConditionWhere(conditionWhenTrue, AiExpUnion.Or);
            else
                this.SetConditionWhere(conditionWhenFalse, AiExpUnion.Or);
        }

        #endregion

        #region  OrderBy语句

        /// <summary>
        /// 添加一个OrderBy语句
        /// </summary>
        /// <typeparam name="D">OrderBy的字段数据类型</typeparam>
        /// <param name="aiExp">OrderBy条件表达示</param>
        public void OrderBy<D>(Expression<Func<T, D>> condition, AiOrderByType type = AiOrderByType.Asc)
        {
            this.SetConditionOrderBy(condition, type);
        }

        /// <summary>
        /// 如果条件满足时,添加一个OrderBy语句
        /// </summary>
        /// <typeparam name="D">OrderBy的数据字段类型</typeparam>
        /// <param name="aiCondition">Lambda条件</param>
        /// <param name="aiExp">OrderBy条件表达示</param>
        public void OrderBy<D>(Func<bool> aiCondition, Expression<Func<T, D>> condition, AiOrderByType type = AiOrderByType.Desc)
        {
            if (aiCondition.Invoke())
                this.SetConditionOrderBy(condition, type);
        }

        /// <summary>
        /// 如果条件满足时,将添加前一个OrderBy语句，否则添加后一个
        /// </summary>
        /// <typeparam name="D">OrderBy的数据字段类型</typeparam>
        /// <param name="aiCondition">Lambda条件</param>
        /// <param name="aiExpWhenTrue">条件为真时</param>
        /// <param name="aiExpWhenFalse">条件为假时</param>
        public void OrderBy<D>(Func<bool> aiCondition, Expression<Func<T, D>> conditionWhenTrue, Expression<Func<T, D>> conditionWhenFalse, AiOrderByType type = AiOrderByType.Desc)
        {
            if (aiCondition.Invoke())
                this.SetConditionOrderBy(conditionWhenTrue, type);
            else
                this.SetConditionOrderBy(conditionWhenFalse, type);
        }

        #endregion

        #region 内部操作

        /// <summary>
        /// 字段矫正
        /// </summary>
        /// <returns></returns>
        private string FieldCorrection(string where, Dictionary<string, FiledParameter> dic)
        {
            if (dic != null && dic.Count > 0 && !string.IsNullOrWhiteSpace(where))
            {
                foreach (var item in dic)
                {
                    where = where
                        .Replace($"({item.Key}", $"({item.Value.name}")
                        .Replace($"{item.Key})", $"{item.Value.name})");
                }
            }
            return where;

        }

        private List<ExpressionResult> expressions = new List<ExpressionResult>();

        private string _aiOrderByStr = string.Empty;

        private void SetConditionOrderBy(Expression condition, AiOrderByType type)
        {
            var itemstr = AiExpressionWriterSql.BizWhereWriteToString(condition, AiExpSqlType.aiOrder);

            if (!string.IsNullOrWhiteSpace(_aiOrderByStr))
                _aiOrderByStr += ",";

            if (type.Equals(AiOrderByType.Desc))
                _aiOrderByStr += itemstr + " desc ";
            else
                _aiOrderByStr += itemstr;
        }

        private void SetConditionWhere(Expression condition, AiExpUnion bizUion = AiExpUnion.And)
        {
            var itemstr = AiExpressionWriterSql.BizWhereWriteToString(condition, AiExpSqlType.aiWhere);

            expressions.Add(new ExpressionResult{ Type = bizUion, value = itemstr });

        }

        #endregion

        #region Model

        

        class ExpressionResult
        {
            public string value { get; set; }
            public AiExpUnion Type { get; set; }
        }

        #endregion

    }
}
